#ifndef CTagData_H
#define CTagData_H
/********************************************************************************
** @ Date:2025/05/23
** @ Author: HanJiaXin
** @ Description:测点数据类
** @ Version:1.0.0
** @ ClassName:CTagData
** @ Fun:
********************************************************************************/
#include <QObject>
#include <time.h>
#include <chrono>
#include <QMutex>
#include <QDateTime>

class CTagData  : public QObject
{
    Q_OBJECT

public:
    //测点类型
    enum enumTagType
    {
        enUint8 = 1,
        enInt16,
        enUint16,
        enInt32,
        enUint32,
        enInt64,
        enUint64,
        enFloat,
        enDouble,
        enString,
    };

    //测点质量
    enum enumTagQuality
    {
        Q_GOOD,       //正常
        Q_SCANOFF,    //强制
        Q_L3,         //越下3限
        Q_LL,         //越下下限
        Q_LO,         //越下限
        Q_UP,         //越上限
        Q_UU,         //越上上限
        Q_U3,         //越上3限
        Q_BAD=8,      //异常
        Q_TIMEOUT=9,  //超时
        Q_DATAERR=10, //数据错误/未读取数据
        Q_DRVERR=11,  //驱动错误
        Q_ADDRERR=12, //地址错误
        Q_SVRERR=13,  //服务错误
        Q_HWERR=14,   //硬件故障
        Q_UNVALID=15,  //无效数据
        Q_UNKOWN=255, //数据错误
    };

    CTagData(QObject* parent = nullptr);
    explicit CTagData(const CTagData& other, QObject* parent = nullptr);//深拷贝构造函数---加入新的成员变量的时候记得实现深拷贝
    CTagData& operator=(const CTagData& other);// 深拷贝赋值运算符---加入新的成员变量的时候记得实现深拷贝赋值运算
    ~CTagData();

    //设置值 字符串
    void setString(const QString &val);
    //设置值 字符串
    void setString(const QByteArray& byte);
    //设置值 非字符串型 入参为大端序数据
    void setBEData(quint64 nData);

    inline void setUint8(const uint8_t &data) { value.byte = data; }
    inline void setInt16(const int16_t &data) { value.n16Num = data; }
    inline void setUint16(const uint16_t &data) { value.un16Num = data; }
    inline void setInt32(const int32_t &data) { value.n32Num = data; }
    inline void setUint32(const uint32_t &data) { value.un32Num = data; }
    inline void setInt64(const int64_t &data) { value.n64Num = data; }
    inline void setUint64(const uint64_t &data) { value.un64Num = data; }
    inline void setFloat(const float &data) { value.fNum = data; }
    inline void setDouble(const double &data) { value.dNum = data; }

    uint8_t toUint8() { return value.byte; }
    int16_t toInt16() { return value.n16Num; }
    uint16_t toUint16() { return value.un16Num; }
    int32_t toInt32() { return value.n32Num; }
    uint32_t toUint32() { return value.un32Num; }
    int64_t toInt64() { return value.n64Num; }
    uint64_t toUint64() { return value.un64Num; }
    float toFloat() { return value.fNum; }
    double toDouble() { return value.dNum; }

    //设置时间戳
    inline void setTimeStamp(quint64 nStamp) { QMutexLocker locker(&m_mutex); m_nTimeStamp = nStamp; }

    inline QDateTime getDateTime() { QMutexLocker locker(&m_mutex); return QDateTime::fromMSecsSinceEpoch(m_nTimeStamp); }
    //获取时间戳
    static uint64_t getTimeStamp()
    {
#if defined(_WIN32) || defined(WIN32)
        using namespace std::chrono;
        // 获取当前时间点（自 Unix 纪元以来）
        auto nowT = system_clock::now();
        // 转换为自 Unix 纪元以来的毫秒数
        auto duration = nowT.time_since_epoch();
        auto tStamp = duration_cast<milliseconds>(duration).count();
        return tStamp;
#elif defined(__linux__)
        uint64_t tStamp;
        timespec ts;
        if (-1 == clock_gettime(CLOCK_REALTIME, &ts)) return 0;
        tStamp = ts.tv_sec * 1000;
        tStamp += ts.tv_nsec / 1000000;
        //std::cout << tStamp << std::endl;
        return tStamp;
#else
#endif
    }
    static std::string getTimeString(uint64_t timestamp = 0)
    {
        // 自动获取当前时间戳（如果未传入参数）
        if (timestamp == 0) timestamp = getTimeStamp();

        // 分解时间戳为秒和毫秒
        const time_t rawtime = static_cast<time_t>(timestamp / 1000);
        const int milliseconds = timestamp % 1000;

        struct tm timeinfo;
        char buffer[80];

        // 线程安全的时间转换
#if defined(_WIN32) || defined(WIN32)
        localtime_s(&timeinfo, &rawtime);
#elif defined(__linux__)
        localtime_r(&rawtime, &timeinfo);
#endif

        // 格式化基础时间
        strftime(buffer, sizeof(buffer), "%Y/%m/%d %H:%M:%S", &timeinfo);

        // 追加毫秒部分
        char finalBuffer[84];
        snprintf(finalBuffer, sizeof(finalBuffer), "%s.%03d", buffer, milliseconds);

        return std::string(finalBuffer);
    }
    //设置字符串长度
    int setDataSize(const int &nSize);
    //设置值 浮点数
    void setValue(const double &val, const uint64_t &tStamp);
    //设置值 浮点数
    void setValue(const double &val);
    //设置值
    int setValue(const CTagData &dest);
    //设置值
    int setValue(const CTagData* &dest);
    //获取值
    void getValue(double *val);
    //获取值
    void getValue(std::string &sVal);
    //复制另一个tag的值
    void copyTag(CTagData* pTag);

    quint8 getQuality() { QMutexLocker locker(&m_mutex); return m_nQuality; }
    void setQuality(quint8 nQuality) { QMutexLocker locker(&m_mutex); m_nQuality = nQuality; }

private:
    //复制联合体
    void copyUnionValue(const CTagData& other);
    //转换联合体内的大端序float
    float getFloatFromBEUnion(quint32 nValue);
    //转换联合体内的大端序double
    double getDoubleFromBEUnion(quint64 nValue);

public:
    //测点属性相关
    quint32 m_nIndex;          //测点索引（4字节）
    QString m_sTagName;        //测点名
    QString m_sTagDesc;        //测点描述
    QString m_sAddr;           //测点地址
    quint8  m_nDataType;       //测点数据类型(1字节) 见CTagData::enumTagType
    quint16 m_nScanRate;       //测点采集周期/扫描频率(ms)
    QString m_sDataAccess;     //读写权限/读写标识
    QString m_sCollectDrv;     //采集驱动
    QString m_sCollectAddr;    //测点采集地址
    QString m_sKeyAddr;        //测点发布地址
    double  m_dDeadband;       //数据死区
    int     m_nExceptionReport;//是否启用例外报告

    //测点实时值相关
    quint8     m_nQuality;           // 测点质量（1字节）
    quint64    m_nTimeStamp;         // 测点数据更新时戳毫秒（8字节）
    quint16    m_nDataSize;          // 数据长度（2字节）
    union MyUnion
    {                              // 使用联合体存储不同类型的值
        quint8     byte;           // 布尔类型（1字节）
        qint16     n16Num;         // 短整型（2字节）
        quint16    un16Num;        // 无符号短整型（2字节）
        qint32     n32Num;         // 整型（4字节）
        quint32    un32Num;        // 无符号整型（4字节）
        qint64     n64Num;         // 长整型（8字节）
        quint64    un64Num;        // 无符号长型（8字节）
        float      fNum;           // 单精度浮点型（4字节）
        double     dNum;           // 双精度浮点型（8字节）
        char*      str;            // 字符串首地址（4字节）
    } value;
    QString     m_sValue;           //字符型数据

    QMutex m_mutex;
};


#endif
